//
//  ABTestExample.swift
//  SwiftCode
//
//  Created by yuhus on 2023/6/12.
//

import Foundation

class ABTestExample: ListViewController {
  override func getItemCount() -> Int {
    data.count
  }
  
  override func getItem(_ indexPath: IndexPath) -> Item {
    data[indexPath.row]
  }
  
  private lazy var data: [Item] = [
    .init(title: "init", description: "初始化 ABTestConfiguration", action: { [weak self] in self?.initConfig() }),
    .init(title: "getABValue", description: "ABValue getter 方法", action: { [weak self] in self?.getABValue() }),
    .init(title: "ABTestEnviroment.local", description: "切换环境 local", action: { [weak self] in self?.changeEnviroment(true) }),
    .init(title: "ABTestEnviroment.online", description: "切换环境 online", action: { [weak self] in self?.changeEnviroment(false) }),
    .init(title: "allABElements", description: "打印所有 ABValue", action: { [weak self] in self?.allABElements() }),
  ]
  
  private func initConfig() {
    ABTestConfiguration.register(PandoraABTest())
  }
  
  private func getABValue() {
    let config = ABConfiguration()
    print("boolValue:", config.boolValue)
    print("intValue:", config.intValue)
    print("stringValue:", config.stringValue)
  }
  
  private var abTestConfig = ABTestConfiguration()
  private func changeEnviroment(_ isLocal: Bool) {
    abTestConfig.environment = isLocal ? .local : .online
  }
  
  private func allABElements() {
    _ = ABConfiguration()
    
    ABTestElement.allElements.forEach { element in
      let key = element.key
      let defaultValue = element.defaultValue
      let onlineValue = abTestConfig.online.getABValue(key: key, default: "@")
      let currentValue = ABTestElement.allValues[key]
      let localValue = abTestConfig.local.getABValue(key: key, default: defaultValue)
      print("element:", element)
      print("onlineValue:", onlineValue)
      print("currentValue:", currentValue ?? "nil")
      print("localValue:", localValue )
    }
  }
}

public protocol ABConfigurationType {
  var boolValue: Bool { get }
  var intValue: Int { get }
  var stringValue: String { get }
}

struct ABConfiguration: ABConfigurationType {
  @ABTestable(key: "key_value_bool", desc: "Bool 值")
  var boolValue: Bool = true
  
  @ABTestable(key: "key_value_int", desc: " Int 值")
  var intValue: Int = 2
  
  @ABTestable(key: "key_value_string", desc: "String 值")
  var stringValue: String = "stringValue"
}

public struct PandoraABTest: ABTestProvider {
  public init() {}
  
  public func getABValue<T>(key: String, default: T) -> T where T: ABValue {
    switch `default` {
    case let value as Bool:
      return !value as? T ?? `default`
    case let value as Int:
      return (value + 1) as? T ?? `default`
    case let value as String:
      return (value + " pandora") as? T ?? `default`
    default:
      assertionFailure("ABTest: Only supported Bool/Int/String")
      return `default`
    }
  }
  public func setABValue<T>(key: String, value: T) -> Bool where T: ABValue { false }
}
